package com.pine.app.module.security.oauth.filter;

import com.pine.app.module.security.core.Authentication;
import com.pine.app.module.security.core.SecurityContextHolder;
import com.pine.app.module.security.core.matcher.RequestMatcher;
import com.pine.app.module.security.core.web.BaseWebFilter;
import com.pine.app.module.security.core.common.enums.ErrorType;
import com.pine.app.module.security.oauth.exception.AuthenticationException;
import com.pine.app.module.security.oauth.provider.sso.request.HttpSessionRequestCache;
import com.pine.app.module.security.oauth.provider.sso.request.RequestCache;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.Order;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author xiaoyuan
 * @create 2020/3/17 23:33
 **/
@Order(60)
public class OAuth2AuthenticationProcessingFilter extends BaseWebFilter {

    private RequestMatcher ignorRequestMatcher;


    private RequestCache requestCache = new HttpSessionRequestCache();

    private String loginPath;
    private static final String JSON_TYPE = "application/json";
    private static final String X_TYPE = "XMLHttpRequest";

    private final String DEFUALT_LOGIN_PATH = "/login";


    public OAuth2AuthenticationProcessingFilter(RequestMatcher ignorRequestMatcher) {
        this.ignorRequestMatcher = ignorRequestMatcher;

    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

        if (ignorRequestMatcher != null && ignorRequestMatcher.matches(httpServletRequest)) {
            filterChain.doFilter(httpServletRequest, httpServletResponse);
            return;
        }
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            //  http 请求头进行判断返回什么类型
            String contentTypeHeader = httpServletRequest.getHeader("Content-Type");
            String acceptHeader = httpServletRequest.getHeader("Accept");
            String xRequestedWith = httpServletRequest.getHeader("X-Requested-With");
            boolean checkIsJson = (contentTypeHeader != null && contentTypeHeader.contains(JSON_TYPE)) || (acceptHeader != null && acceptHeader.contains(JSON_TYPE)) || X_TYPE.equalsIgnoreCase(xRequestedWith);
            if (checkIsJson) {
                ErrorType.AUTHENTICATION_ERROR.throwThis(AuthenticationException::new);
            }
            redictToLogin(httpServletRequest, httpServletResponse);
            return;
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private void redictToLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        requestCache.saveRequest(request, response);
        response.sendRedirect(request.getContextPath() + (StringUtils.isBlank(loginPath) ? DEFUALT_LOGIN_PATH : loginPath));
        response.flushBuffer();
    }

    public String getLoginPath() {
        return loginPath;
    }

    public void setLoginPath(String loginPath) {
        this.loginPath = loginPath;
    }
}
